﻿#include "stdafx.h"
#include "CodeGenerate/BlockGen.h"
#include "utility.h"
#include "AstNode.h"
#include "Parameter.h"
#include "Temporary.h"
#include "BlockContext.h"


struct Data;
#include "token.h"

/**
 *	这个函数尝试对基本变量进行隐式转换
 */
using namespace llvm;
Value* try_cast( IRBuilder<>& builder, Type* tp, Value *v ) {
	using namespace llvm;

	if (!tp || !v) return v;

	Type* r = v->getType();
	if (tp->isStructTy()) return v;

	if (tp->isIntegerTy() && r->isIntegerTy()) {
		return builder.CreateSExtOrTrunc( v, tp );
	} else if (tp->isFloatingPointTy() && r->isFloatingPointTy()) {
		if (tp->getIntegerBitWidth() > r->getIntegerBitWidth()) {
			return builder.CreateFPExt( v, tp );
		} else if (tp->getIntegerBitWidth() < r->getIntegerBitWidth()) {
			return builder.CreateFPTrunc( v, tp );
		} else {
			return v;
		}
	} else if (tp->isIntegerTy() && r->isFloatingPointTy()) {
		return builder.CreateFPToSI( v, tp );
	} else if (tp->isFloatingPointTy() && r->isIntegerTy()) {
		return builder.CreateSIToFP( v, tp );
	} else {
		return builder.CreateBitOrPointerCast( v, tp );
	}
}

/// 把操作符转换成字符串
std::string operator_to_str(int op) {
	switch (op)
	{
	case LEFTMOVE:
		return "<<";
	case RIGHTMOVE:
		return ">>";
	case URIGHTMOVE:
		return ">>>";
	case LEQ:
		return "<=";
	case REQ:
		return ">=";
	case RGO:
		return "=>";
	case EQ:
		return "==";
	case AEQ:
		return ":=";
	case NOEQ:
		return "!=";
	case OR:
		return "||";
	case AND:
		return "&&";
	case INC:
		return "++";
	case DEC:
		return "--";
	case ARRAY:
		return "->";
	case ISOPT:
		return "is";
	default:
		return std::string(1, (char)op);
	}
}

Value * int_to_bool(IRBuilder<>& builder, Value * v)
{
	auto type=v->getType();
	if (!type->isIntegerTy()) throw std::runtime_error("无法转换成布尔类型");

	int w = type->getScalarSizeInBits();
	if (1 == w ) return v;	// 本来就是布尔类型（i1）

	auto x = IntegerType::get(builder.getContext(), w); 
	Value* zero=ConstantInt::getSigned(x, 0);
	return builder.CreateICmpNE(v, zero);
}

BlockGen * makeCodeGenList(SiContext * parent, std::vector<AstNode*>& lines)
{
	auto x = new BlockGen();
	auto *p = new BlockContext(parent);
	for (auto i : lines) {
		auto o=i->makeGen(p);
		x->codes.push_back(o);
	}
	return x;
}
